(function($){

	var _labels = {};
	
	var loadMethods = {
		'object' : function(labels){
			if (labels instanceof Array){
				$(labels).each(function(index, item){
					$.loadMessages(item);
				});
			}
			else{
				_labels = $.extend(_labels, labels);
			}
		},
		'function' : function(fn){
			$.loadMessages(fn());
		},
		'string' : function(string){
			var s = $(string.split(/[\n\r]/));
			var labels = {};
			s.each(function(index, item){
				item = $.trim(item);
				if (item){
					var cutIndex = item.indexOf('=');
					var s = [item.substring(0, cutIndex), item.substring(cutIndex + 1)];
					labels[s[0]] = s[1];
				}
			});
			$.loadMessages(labels);
		}
	}
	$.extend({
		/**
		 * Replace the token '{key}' in a string with its value in the map passed
		 * eg. replaceToken('Hello {name}', {name : 'Manuel'}); will return the string 'Hello Manuel'
		 */
		replaceToken : function(string, map){
			if (map){
				for (var s in map){
					string = string.replace('{' + s + '}', map[s]);
				}
			}
			return string;
		},
		/**
		 * Load the messages to be reused later. Can pass a string formatted like 'key1=value\nkey2=value2' or an object {key1:value, key2:value2},
		 * an array of object, string or function. If you pass a function (an array or a single function) 
		 * the results can be a string, an object, an array or a function and will be loaded.
		 */
		loadMessages : function(labels){
			var to = typeof labels;
			if (loadMethods[to]){
				loadMethods[to](labels);
			}
			else{
				$.error(labels + ' isn\'t a valid element to load messages');
			}
		},
		message : function(settings, o){
			if (arguments.length == 0){
				//if there aren't parameters returns all the labels
				return _labels;
			}
			var parameters = {
				key : '',
				params : '',
				extendendLabels : {},
				useData : false,
				useId : false
			};
			var l; //will contains all the labels
			if (typeof settings !== 'string'){
				
				$.extend(parameters, settings);
				
				l = $.extend({}, _labels, parameters.extendedLabels);
				
				if (o){ //if o exists change its inner html
					$(o).each(function(index, item){
						var $this = $(this);
						
						var key = parameters.key;
						var params = parameters.params;
						
						if (parameters.useData){ //extend the parameters with the object data
							if (typeof parameters.useData == 'string'){
								params = $.extend(params, $this.data(parameters.useData));
							}
							else{
								params = $.extend(params, $this.data());
							}
						}
						if (parameters.useId){ //use the object id as key
							key = $this.attr('id');
						}
						$this.html($.replaceToken(l[key], params)); 
					});
					return $(o);
				}
				
			}
			else{
				/*
				 * In this case the 'settings' variable is a string that represents the
				 * key of the label, so create the parameters.
				 */
				$.extend(parameters, {key : settings});
				l = _labels;
			}
			
			return $.replaceToken(l[parameters.key], parameters.params); //return the string if the object don't exists
			
		}
	});
	
	$.fn.message = function(settings){
		$.message(settings, this);
		return this;
	}
	
})(jQuery);